package com.google.code.securityflow.util

object MapUtil {

  def merge[K, V](mapA: Map[K, V], mapB: Map[K, V])(merge: (V, V) => V): Map[K, V] = {
    val (keysA, keysB) = (mapA.keySet, mapB.keySet);
    val sharedKeys = mapA.keySet & mapB.keySet;
    val (keysOnlyA, keysOnlyB) = (keysA -- sharedKeys, keysB -- sharedKeys);

    val merged = sharedKeys.foldLeft(Map.empty: Map[K, V])((m, key) => m + ((key -> merge(mapA(key), mapB(key)))));
    val onlyA = mapA.filterKeys(k => keysOnlyA(k));
    val onlyB = mapB.filterKeys(k => keysOnlyB(k));

    onlyA ++ merged ++ onlyB;
  }

  def mergeFold[K, V](mapA: Map[K, V], mapB: Map[K, V])(merge: (V, V) => V)(left: V => V)(right: V => V): Map[K, V] = {
    val (keysA, keysB) = (mapA.keySet, mapB.keySet);
    val sharedKeys = mapA.keySet & mapB.keySet;
    val (keysOnlyA, keysOnlyB) = (keysA -- sharedKeys, keysB -- sharedKeys);

    val merged = sharedKeys.foldLeft(Map.empty: Map[K, V])((m, key) => m + ((key -> merge(mapA(key), mapB(key)))));
    val onlyA = mapA.filterKeys(k => keysOnlyA(k));
    val onlyB = mapB.filterKeys(k => keysOnlyB(k));

    onlyA.mapValues(left) ++ merged ++ onlyB.mapValues(right);
  }

}